package models

import (
	"github.com/astaxie/beego/orm"
	_ "github.com/mattn/go-sqlite3"
	"os"
	"path"
	"servermg/log"
	"strconv"
	"time"
)

const (
	_DB_NAME   = "data/data.db"
	_DB_DRIVER = "sqlite3"
)

const (
	OPT_LOG_INFO       = 1 // 日志配制
	OPT_SLOT_CONFIG    = 2 //老虎机数值配制
	OPT_HUNDRED_CONFIG = 3 //百人牛牛数值配制
	OPT_RETIRE         = 4 //退休控制
)

var Opts []int = []int{OPT_LOG_INFO, OPT_SLOT_CONFIG, OPT_HUNDRED_CONFIG, OPT_RETIRE}

func init() {
	orm.RegisterModel(new(ServerType), new(Server), new(ServerOpt))
}

// IsExist checks whether a file or directory exists.
// It returns false when the file or directory does not exist.
func IsExist(path string) bool {
	_, err := os.Stat(path)
	return err == nil || os.IsExist(err)
}

func RegisterDB() {
	if !IsExist(_DB_NAME) {
		os.MkdirAll(path.Dir(_DB_NAME), os.ModePerm)
		os.Create(_DB_NAME)
	}

	// 参数1   driverName
	// 参数2   数据库类型
	// 这个用来设置 driverName 对应的数据库类型
	// mysql / sqlite3 / postgres 这三种是默认已经注册过的，所以可以无需设置
	orm.RegisterDriver(_DB_DRIVER, orm.DRSqlite)

	orm.RegisterDataBase("default", _DB_DRIVER, _DB_NAME, 10)

	// 设置为 UTC 时间
	orm.DefaultTimeLoc = time.UTC

}

type GameInfo struct {
	ServerID   int32
	Port       int32
	Retire     bool
	UserCount  int32
	TableCount int32
	CreateTime string
	AutoExit   bool
}

type Alloc struct {
	Addr       string
	Level      int32
	Count      int32
	GameServer []*GameInfo
}

type ServerLog struct {
	Server
	OldLv int
	CurLv int
}

//server类型
type ServerType struct {
	Id   int64  `orm:"auto"`
	Name string `orm:"size(20);unique"`
	Desc string `orm:"size(100)"`
}

type Server struct {
	Id    int64 `orm:"auto"`
	Name  string
	Addr  string
	Port  int
	Svid  int
	SType *ServerType `orm:"rel(fk)"`
}

type ServerOpt struct {
	Id   int64 `orm:"auto"`
	Stid int64 //server的类型ID
	Opt  int   //server的操作码
}

func AddSType(name, desc string, opts []int) error {
	o := orm.NewOrm()
	cate := &ServerType{Name: name, Desc: desc}

	qs := o.QueryTable("server_type")
	err := qs.Filter("name", name).One(cate)

	if err == nil {
		log.Error("has type %s:%s", name, desc)
		return err
	} else {
		log.Debug("AddSType err :", err.Error())
	}

	_, err = o.Insert(cate)

	if len(opts) > 0 {
		for _, opt := range opts {
			AddServerOpt(cate.Id, opt)
		}
	}

	return err
}

func DelSType(id string) error {
	log.Error("del id[%v]", id)
	o := orm.NewOrm()
	id_num, err := strconv.ParseInt(id, 10, 64)
	if err != nil {
		return err
	}
	stype := &ServerType{Id: id_num}

	servers := make([]*Server, 0)
	qs := o.QueryTable("server")
	_, err = qs.Filter("SType", stype).All(&servers)
	for i := 0; i < len(servers); i++ {
		_, err = o.Delete(servers[i])
	}
	o.Delete(stype)

	return err
}

func GetStypeById(id int64) *ServerType {
	log.Error("qeury stype id [%d]", id)
	o := orm.NewOrm()
	stype := &ServerType{Id: id}
	err := o.Read(stype)
	if err != nil {
		log.Debug(err.Error())
		return nil
	}

	return stype
}

func GetAllSTypes() ([]*ServerType, error) {
	o := orm.NewOrm()
	cates := make([]*ServerType, 0)
	qs := o.QueryTable("server_type")
	_, err := qs.All(&cates)

	return cates, err
}

func AddServer(svid, stype, name, addr, port string) error {
	svid_id, err := strconv.ParseInt(svid, 10, 64)
	port_id, err := strconv.ParseInt(port, 10, 64)
	stype_id, err := strconv.ParseInt(stype, 10, 64)

	st := &ServerType{Id: stype_id}

	server := &Server{Name: name, Addr: addr, Svid: int(svid_id), Port: int(port_id), SType: st}

	o := orm.NewOrm()
	qs := o.QueryTable("server")
	err = qs.Filter("port", port_id).One(server)

	if err == nil {
		return err
	}

	_, err = o.Insert(server)

	return err
}

func GetServerById(id int64) *Server {
	log.Error("qeury server id [%d]", id)
	o := orm.NewOrm()
	server := &Server{Id: id}
	err := o.Read(server)
	if err != nil {
		log.Debug(err.Error())
		return nil
	}

	return server
}

func GetStypeServer(stype string) ([]*Server, error) {
	stype_id, err := strconv.ParseInt(stype, 10, 64)
	st := &ServerType{Id: stype_id}
	servers := make([]*Server, 0)

	o := orm.NewOrm()
	qs := o.QueryTable("server")
	_, err = qs.Filter("SType", st).All(&servers)
	return servers, err
}

func AddServerOpt(stid int64, opt int) {
	log.Error("add stype[%d],opt[%d]", stid, opt)
	sopt := &ServerOpt{Stid: stid, Opt: opt}

	o := orm.NewOrm()
	qs := o.QueryTable(sopt)
	exist := qs.Filter("stid", stid).Filter("opt", opt).Exist()
	if exist {
		log.Error("aready exist stdi[%d],opt[%d]")
	} else {
		o.Insert(sopt)
	}
}

func GetStypeByOpt(opt int) []*ServerType {
	sopts := make([]*ServerOpt, 0)
	o := orm.NewOrm()
	qs := o.QueryTable("server_opt")
	num, err := qs.Filter("opt", opt).All(&sopts)
	log.Debug("num %d, err :%s", num, err)
	sts := make([]*ServerType, 0)
	for _, sopt := range sopts {
		stype := GetStypeById(sopt.Stid)
		if stype != nil {
			sts = append(sts, stype)
		} else {
			o.Delete(sopt)
			log.Error("find stype[%d] error delete opt [%d]", sopt.Stid, sopt.Id)
		}
	}

	return sts
}
